package com.suray.wcs.service.hk.agv.system.process;

import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.wcs.service.hk.agv.bean.HkAgvCallBack;
import com.suray.wcs.service.hk.agv.core.HkAgvTask;
import com.suray.wcs.service.hk.agv.extern.function.HkAgvExternFunc;
import com.suray.wcs.service.hk.agv.type.HkAgvProcessType;
import com.suray.wcs.service.hk.agv.type.HkAgvTaskReportInfo;
import com.suray.wcs.service.hk.agv.type.HkAgvTaskStatus;
import com.suray.wcs.service.test.base.BaseThread;

public class HkAgvProcess extends BaseThread {
    private HkAgvTask task;

    private HkAgvProcessType process;

    /**
     * agv流程结束标志位
     */
    private boolean isProEnd;

    public HkAgvProcess(HkAgvTask task) {
        super("AgvTask--" + task.getTaskId(), 1000);
        this.task = task;
        isProEnd = false;
        task.setIsExec(true);
    }

    /**
     * 获取任务信息
     * @return
     */
    public HkAgvTask getTask() {
        return task;
    }

    /**
     * 更新任务进度
     */
    private synchronized void freshTaskPro(HkAgvProcessType process) {
        this.process = process;
        task.setTaskPro(process.getValue());
        LoggerUtil.info("Agv任务进度更新为->" + this.process + ":" + this, this.getClass());
    }

    /**
     * Agv流程初始化
     */
    public void init() {
        LoggerUtil.info("Agv任务开始执行:" + task, this.getClass());
        process = HkAgvProcessType.parseProcess(task.getTaskPro());
        start();
    }

    /**
     * 初始化任务
     */
    public void initTask() {
        task.setTaskStatus(HkAgvTaskStatus.INIT.getValue());
        process = HkAgvProcessType.INIT;
    }

    /**
     * 任务恢复
     */
    public void recoveryTask() {
        HkAgvTaskStatus taskStatus = HkAgvTaskStatus.parseStatus(task.getTaskStatus());
        switch (taskStatus) {
            case ERROR:
            case TASK_SEND_FAIL:
            case TASK_CONTINUE_SEND_FAIL:
                task.setTaskStatus(HkAgvTaskStatus.RUN.getValue());
            default:
                throw new RuntimeException("当前状态不允许恢复");
        }
    }

    /**
     * 修改任务进度
     * @param process
     */
    public void changeTaskProcess(HkAgvProcessType process) {
        freshTaskPro(process);
        task.setTaskStatus(HkAgvTaskStatus.RUN.getValue());
    }

    @Override
    protected void process() {
        HkAgvTaskStatus taskStatus = HkAgvTaskStatus.parseStatus(task.getTaskStatus());
        if (taskStatus.equals(HkAgvTaskStatus.ERROR)
                || taskStatus.equals(HkAgvTaskStatus.TASK_SEND_FAIL)
                || taskStatus.equals(HkAgvTaskStatus.TASK_CONTINUE_SEND_FAIL)) {
            //任务故障
            return;
        }

        switch (process) {
            case INIT:
                sendTaskToAgv(task);
                break;
            case GO_TO_START:
                break;
            case REACH_OUT_START:
                reachOutStart();
                break;
            case SEND_AGV_INTO_START:
                sendAgvIntoStart();
                break;
            case INTO_START_POINT:
                break;
            case GET_CARGO:
                getCargoEnd();
                break;
            case WAIT_AGV_OUT_OF_START:
                break;
            case OUT_OF_START:
                outOfStart();
                break;
            case GO_TO_END:
                break;
            case REACH_OUT_END:
                reachOutEnd();
                break;
            case SEND_AGV_INTO_END:
                sendAgvIntoEnd();
                break;
            case INTO_END_POINT:
                break;
            case PUT_CARGO:
                putCargoEnd();
                break;
            case WAIT_AGV_OUT_OF_END:
                break;
            case OUT_OF_END:
                outOfEnd();
                break;
            case END:
                LoggerUtil.info("Agv任务结束：" + task, this.getClass());
                task.setTaskStatus(HkAgvTaskStatus.FINISH.getValue());
                isProEnd = true;
                endThread();
                break;
            default:
                break;
        }
    }

    /**
     * 任务发送至Agv
     */
    private void sendTaskToAgv(HkAgvTask task) {
        if (HkAgvExternFunc.hkSendTask(task)) {
            freshTaskPro(HkAgvProcessType.GO_TO_START);
            task.setTaskStatus(HkAgvTaskStatus.RUN.getValue());
        } else {
            task.setTaskStatus(HkAgvTaskStatus.TASK_SEND_FAIL.getValue());
        }
    }

    /**
     * Agv到达取货点外面，检测取货点是否允许进入
     */
    private void reachOutStart() {
        if (HkAgvExternFunc.hkAgvIntoPoint(task.getStartPrePoint(), task.getStartPoint(),
                task.getAgvId(), true)) {
            LoggerUtil.info(task.getStartPoint() + "允许进入：" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.SEND_AGV_INTO_START);
        }
    }

    /**
     * 发送Agv进入取货点信号
     */
    private void sendAgvIntoStart() {
        if (sendTaskContinue(task.getTaskId())) {
            LoggerUtil.info("发送Agv进入取货点成功：" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.INTO_START_POINT);
        } else {
            task.setTaskStatus(HkAgvTaskStatus.TASK_CONTINUE_SEND_FAIL.getValue());
        }
    }

    /**
     * Agv取货完成,发送Agv离开取货点信号
     */
    private void getCargoEnd() {
        if (sendTaskContinue(task.getTaskId())) {
            LoggerUtil.info("Agv取货完成, 发送Agv离开取货点成功" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.WAIT_AGV_OUT_OF_START);
        } else {
            task.setTaskStatus(HkAgvTaskStatus.TASK_CONTINUE_SEND_FAIL.getValue());
        }
    }

    /**
     * Agv取货完成离开取货点
     */
    private void outOfStart() {
        if (sendTaskContinue(task.getTaskId())) {
            LoggerUtil.info("发送Agv前往终点成功：" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.GO_TO_END);
        } else {
            task.setTaskStatus(HkAgvTaskStatus.TASK_CONTINUE_SEND_FAIL.getValue());
        }
    }

    /**
     * Agv到达放货点外面
     */
    private void reachOutEnd() {
        if (HkAgvExternFunc.hkAgvIntoPoint(task.getEndPrePoint(), task.getEndPoint(),
                task.getAgvId(), false)) {
            LoggerUtil.info(task.getEndPoint() + "允许进入：" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.SEND_AGV_INTO_END);
        }
    }

    /**
     * 发送Agv进入放货点信号
     */
    private void sendAgvIntoEnd() {
        if (sendTaskContinue(task.getTaskId())) {
            LoggerUtil.info("发送Agv进入放货点完成:" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.INTO_END_POINT);
        } else {
            task.setTaskStatus(HkAgvTaskStatus.TASK_CONTINUE_SEND_FAIL.getValue());
        }
    }

    /**
     * Agv放货完成，发送Agv离开取货点信号
     */
    private void putCargoEnd() {
        if (sendTaskContinue(task.getTaskId())) {
            LoggerUtil.info("Agv放货完成，发送离开放货点成功:" + task, this.getClass());
            freshTaskPro(HkAgvProcessType.WAIT_AGV_OUT_OF_END);
        } else {
            task.setTaskStatus(HkAgvTaskStatus.TASK_CONTINUE_SEND_FAIL.getValue());
        }
    }

    /**
     * Agv离开放货点
     */
    private void outOfEnd() {
        LoggerUtil.info("Agv离开放货点，任务结束:" + task, this.getClass());
        freshTaskPro(HkAgvProcessType.END);
    }

    /**
     * Agv任务信息反馈
     * @param callBack
     */
    public void agvCallBack(HkAgvCallBack callBack) {
        HkAgvTaskReportInfo reportInfo = HkAgvTaskReportInfo.parseReport(callBack.getMethod());
        switch (reportInfo) {
            case START:
                start(callBack);
                break;
            case ASK_FOR_INTO_START:
                askForIntoStart(callBack);
                break;
            case GET_CARGO:
                getCargo(callBack);
                break;
            case LEAVE_START_POINT:
                leaveStartPoint(callBack);
                break;
            case ASK_FOR_INTO_END:
                askForIntoEnd(callBack);
                break;
            case PUT_CARGO:
                putCargo(callBack);
                break;
            case LEAVE_END_POINT:
                leaveEndPoint(callBack);
                break;
            default:
                LoggerUtil.warn("未设置对应的信息处理:" + callBack + task, this.getClass());
                break;
        }
    }

    /**
     * Agv开始执行任务
     */
    private void start(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv开始执行任务：" + task, this.getClass());

        if (process != HkAgvProcessType.INIT) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.GO_TO_START
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        freshTaskPro(HkAgvProcessType.GO_TO_START);
    }

    /**
     * Agv请求进入取货点取货
     */
    private void askForIntoStart(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv请求进入取货：" + task, this.getClass());

        if (process != HkAgvProcessType.GO_TO_START) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.REACH_OUT_START
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        freshTaskPro(HkAgvProcessType.REACH_OUT_START);
    }

    /**
     * Agv取货完成
     */
    private void getCargo(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv取货完成：" + task, this.getClass());

        if (process != HkAgvProcessType.INTO_START_POINT) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.GET_CARGO
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        HkAgvExternFunc.hkAgvGetCargo(task.getStartPoint());
        freshTaskPro(HkAgvProcessType.GET_CARGO);
    }

    /**
     * Agv离开取货点
     */
    private void leaveStartPoint(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv离开取货点：" + task, this.getClass());

        if (process != HkAgvProcessType.WAIT_AGV_OUT_OF_START) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.OUT_OF_START
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        HkAgvExternFunc.hkAgvOutPoint(task.getAgvId(), task.getStartPoint());
        freshTaskPro(HkAgvProcessType.OUT_OF_START);
    }

    /**
     * Agv请求进入放货点放货
     */
    private void askForIntoEnd(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv请求进入放货：" + task, this.getClass());

        if (process != HkAgvProcessType.GO_TO_END) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.REACH_OUT_END
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        HkAgvExternFunc.hkAgvIntoPoint(task.getEndPrePoint(), task.getEndPoint(), task.getAgvId(), false);
        freshTaskPro(HkAgvProcessType.REACH_OUT_END);
    }

    /**
     * Agv放货完成
     */
    private void putCargo(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv放货完成：" + task, this.getClass());

        if (process != HkAgvProcessType.INTO_END_POINT) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.PUT_CARGO
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        HkAgvExternFunc.hkAgvPutCargo(task.getEndPoint());
        freshTaskPro(HkAgvProcessType.PUT_CARGO);
    }

    /**
     * Agv离开放货点
     */
    private void leaveEndPoint(HkAgvCallBack callBack) {
        LoggerUtil.info("Agv离开放货点：" + task, this.getClass());

        if (process != HkAgvProcessType.WAIT_AGV_OUT_OF_END) {
            LoggerUtil.warn("Agv状态错误：" + process + "，强制修改为：" + HkAgvProcessType.OUT_OF_END
                    , this.getClass());
        }

        task.setAgvId(callBack.getRobotCode());
        HkAgvExternFunc.hkAgvOutPoint(task.getAgvId(), task.getEndPoint());
        freshTaskPro(HkAgvProcessType.OUT_OF_END);
    }

    /**
     * 发送Agv任务继续
     * @param taskId ：继续任务的任务id
     */
    private boolean sendTaskContinue(Integer taskId) {
        return HkAgvExternFunc.hkSendTaskContinue(taskId.toString());
    }

    /**
     * 流程是否结束
     * @return
     */
    public boolean isProcessEnd() {
        return isProEnd;
    }

    @Override
    public String toString() {
        return "HkAgvProcess{" +
                "task=" + task +
                ", process=" + process +
                ", isProEnd=" + isProEnd +
                '}';
    }
}
